package com.maiji.cloud.utils;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.*;
import com.nuomi.common.NuomiApiException;
import com.nuomi.common.NuomiConstants;
import com.nuomi.util.StreamUtil;
import com.nuomi.util.codec.Base64;
import org.apache.commons.lang.StringUtils;

/**
 * 签名工具类
 * 目前只支持rsa方式  不支持rsa2
 */
public class NuomiSignature {

    public static final String appKey = "MMUBBH";
    public static final String dealId = "587621209";
    public static final String PUB_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC4LUN7haAd4SAHlgdsmKRUG+Hc4jdX32HT4wjWjs9kumjqEXK3h2IgrJ1f23knA7whZBFxHoBY4Kw6NrlN8ctRASOxMbAmr8GHa2SjN6wChnQHCNlTtgBCC4XzYw3vi/j2tzedFYo7wsUKmaApUVTat3ksHRbkMhz6siAQrOnOgQIDAQAB";
    public static final String PRIVATE_KEY = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALgtQ3uFoB3hIAeWB2yYpFQb4dziN1ffYdPjCNaOz2S6aOoRcreHYiCsnV/beScDvCFkEXEegFjgrDo2uU3xy1EBI7ExsCavwYdrZKM3rAKGdAcI2VO2AEILhfNjDe+L+Pa3N50VijvCxQqZoClRVNq3eSwdFuQyHPqyIBCs6c6BAgMBAAECgYEAjveL78GtpiQQUfMzNihTP3sZW/Y6Ubr0XJ9bR/o5oY5WTIRY0YCFOqnjy/o5VIDAtAbSx0WPCe71oobCV2//i0Huy4ghao8eNjAXDXAy+7v5WAgMQ2cLtLS944c50NkvqBlHMsUFM8+s3YfVMJV1GplCMbL0eSKAgATzK3k0rDECQQDw+dAGHd/KB0PMI1IvCXQtag9ferMOdQwUfxTS8/pMrCzmHIERg3YCEqXB5redY0s5nqliTpuDt2AReOi9gXP1AkEAw6jjb16iN8r5bocZfiSz3NSL1LmdzgJIUzFHZZklGldlCJGSHnIAz34zFNTAYIwq7Ci5tHnptbXeeT7Naklk3QJAYXQl9NNQFdwqRvxh2DPykAs8fFia4VXktMVQHqAcsbVP0x/j8rk/mEcCUhCEYVouqfbIecFgkzwt1eMX/MvFoQJBAIvK1vRzQKNsOdpmXChsQLW+hkludPkDWHlX9BL64C950Y3Vs/hcq4eUOxrfBrP0cZZZYpU3pWtWjaVC4bDWz2ECQBp3/Mv4Kx5E9sgsq+NWs+pBd1tCeknPFRPIScf5mI10+nv8EpU4555s8/UQUJchxWVecXXjAjV6Vg8ue6p51eM=";

    public static void main (String[] args) throws NuomiApiException {
        HashMap apiParams = new HashMap();
        apiParams.put("appKey", appKey);
        apiParams.put("dealId", dealId);
        apiParams.put("totalAmount", "100");
        apiParams.put("tpOrderId", "1234567890987654321");

        String rsaSign = NuomiSignature.genSignWithRsa(apiParams, PRIVATE_KEY);
        System.out.println(rsaSign);

        boolean b = NuomiSignature.checkSignWithRsa(apiParams, PUB_KEY, rsaSign);
        System.out.println(b);
    }

    public static String genSignWithRsa(String totalAmount, String tpOrderId) throws NuomiApiException {
        HashMap apiParams = new HashMap();
        apiParams.put("appKey", appKey);
        apiParams.put("dealId", dealId);
        apiParams.put("totalAmount", totalAmount);
        apiParams.put("tpOrderId", tpOrderId);

        return NuomiSignature.genSignWithRsa(apiParams, NuomiConstants.PRIVATE_KEY);
    }

    public static Boolean checkSignWithRsa(String totalAmount, String tpOrderId, String rsaSign) throws NuomiApiException {
        HashMap apiParams = new HashMap();
        apiParams.put("appKey", appKey);
        apiParams.put("dealId", dealId);
        apiParams.put("totalAmount", totalAmount);
        apiParams.put("tpOrderId", tpOrderId);

        return NuomiSignature.checkSignWithRsa(apiParams, PUB_KEY, rsaSign);
    }

    /**
     * 获取签名
     *
     * @param sortedParams 排序后的参数
     * @param privateKey   私钥
     * @return 返回签名后的字符串
     * @throws NuomiApiException
     */
    public static String genSignWithRsa(Map<String, String> sortedParams, String privateKey) throws NuomiApiException {
        String sortedParamsContent = getSignContent(sortedParams);
        return rsaSign(sortedParamsContent, privateKey, NuomiConstants.CHARSET_UTF8);
    }

    /**
     * 签名验证
     *
     * @param sortedParams
     * @param pubKey
     * @param sign
     * @return
     * @throws NuomiApiException
     */
    public static boolean checkSignWithRsa(Map<String, String> sortedParams, String pubKey, String sign) throws NuomiApiException {
        String sortedParamsContent = getSignContent(sortedParams);
        return doCheck(sortedParamsContent, sign, pubKey, NuomiConstants.CHARSET_UTF8);
    }

    /**
     * @param sortedParams 已经排序的字符串
     * @return 返回签名后的字符串
     */
    public static String getSignContent(Map<String, String> sortedParams) {
        StringBuffer content = new StringBuffer();
        List<String> keys = new ArrayList<String>(sortedParams.keySet());
        Collections.sort(keys);
        int index = 0;
        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            String value = sortedParams.get(key);
            content.append((index == 0 ? "" : "&") + key + "=" + value);
            index++;

        }
        return content.toString();
    }

    /**
     * sha1WithRsa 加签
     *
     * @param content    需要加密的字符串
     * @param privateKey 私钥
     * @param charset    字符编码类型  如：utf8
     * @return
     * @throws NuomiApiException
     */
    public static String rsaSign(String content, String privateKey, String charset) throws NuomiApiException {
        try {
            PrivateKey priKey = getPrivateKeyFromPKCS8(NuomiConstants.SIGN_TYPE_RSA,
                    new ByteArrayInputStream(privateKey.getBytes()));

            java.security.Signature signature = java.security.Signature
                    .getInstance(NuomiConstants.SIGN_ALGORITHMS);

            signature.initSign(priKey);

            if (StringUtils.isEmpty(charset)) {
                signature.update(content.getBytes());
            } else {
                signature.update(content.getBytes(charset));
            }

            byte[] signed = signature.sign();

            return new String(Base64.encodeBase64(signed));
        } catch (InvalidKeySpecException ie) {
            throw new NuomiApiException("RSA私钥格式不正确，请检查是否正确配置了PKCS8格式的私钥", ie);
        } catch (Exception e) {
            throw new NuomiApiException("RSAcontent = " + content + "; charset = " + charset, e);
        }
    }

    public static PrivateKey getPrivateKeyFromPKCS8(String algorithm, InputStream ins) throws Exception {
        if (ins == null || StringUtils.isEmpty(algorithm)) {
            return null;
        }

        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);

        byte[] encodedKey = StreamUtil.readText(ins).getBytes();

        encodedKey = Base64.decodeBase64(encodedKey);

        return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encodedKey));
    }

    /**
     * RSA验签名检查
     *
     * @param content   待签名数据
     * @param sign      签名值
     * @param publicKey 分配给开发商公钥
     * @param encode    字符集编码
     * @return 布尔值
     * @throws NuomiApiException
     */
    private static boolean doCheck(String content, String sign, String publicKey, String encode) throws NuomiApiException {
        try {
            KeyFactory keyFactory = KeyFactory.getInstance(NuomiConstants.SIGN_TYPE_RSA);
            byte[] bytes = publicKey.getBytes();
            byte[] encodedKey = Base64.decodeBase64(bytes);
            PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
            java.security.Signature signature = java.security.Signature.getInstance(NuomiConstants.SIGN_ALGORITHMS);

            signature.initVerify(pubKey);
            signature.update(content.getBytes(encode));

            boolean bverify = signature.verify(Base64.decodeBase64(sign.getBytes()));
            return bverify;

        } catch (Exception e) {
            throw new NuomiApiException("RSA私钥格式不正确，请检查是否正确配置了PKCS8格式的私钥", e);
        }
    }

}

